<?php

/**
 * Une partie, aussi simple que cela puisse être
 * @author Cyril
 */
class Partie {

    /**
     * Identifiant de la partie (pour le stockage)
     * @var int Identifiant de la partie
     */
    private $idPartie = null;
    /**
     *  Tableau des joueurs
     * @var Array<nomJoueur> Joueurs de la partie. La clée est un int
     */
    private $joueurs = array();
    /**
     *  Indique le joueurs qui a le droit de jouer
     * @var int Compris entre 0 et sizeof($this->joueurs)
     */
    private $tours = 0;
    /**
     * Indique le sens du jeu (nessecaire au lorsqu'on passe au joueur suivant)
     * @var int{0,1} <ul><li>0 si le sens est inversé</li><li>1 sinon</li></ul>
     */
    private $sens = 1;
    /**
     * Nom de la partie
     * @var string
     */
    private $nomPartie;
    private $debut;
    /**
     *  DB Sqlite associé a l'objet
     * @var SQLITE_resource 
     */
    private $db;

    /**
     *
     * @param int/string $idPartie <ul><li>Si type=int alors récupère dans la base de donnée (ne pas oublier de cast avec intval</li>
     * <li>Si type=string alors créée une nouvelle partie</li></ul>
     * @param SQLite_resource $db ressource SQLite;
     */
    public function __construct($idPartie, $db) {
        log_it(__METHOD__, 1);
        $this->db = $db;
        if (is_int($idPartie)) {
            log_it("SELECT", 0);
            $q = mysql_query("
                SELECT * FROM partie
                WHERE idpartie=$idPartie");
            if ($q && $d = mysql_fetch_array($q)) {
                log_it("idPartie : " . intval($d["idpartie"]), 0);
                $this->idPartie = intval($d["idpartie"]);
                $this->nomPartie = $d["nompartie"];
                $this->sens = intval($d["sens"]);
                $this->tours = intval($d["tours"]);
                $this->debut = '1' == $d["debut"];
                $this->getJoueurs();
            } else {
                log_it("(Partie non trouvée)", 0);
                log_it("/" . __METHOD__, -1);
                return null;
            }
        } elseif (is_string($idPartie)) {
            $idPartie = mysql_real_escape_string($idPartie);
            log_it("Ajout d'une partie", 0);
            mysql_query("
                INSERT INTO partie VALUES(
                    null,
                    '$idPartie',
                    '1',
                    '0',
                    '0');");
            $this->idPartie = mysql_insert_id();
            $this->nomPartie = $idPartie;
            log_it($this->idPartie + ' ' + $this->nomPartie, 0);
        }
        log_it("/" . __METHOD__, -1);
    }

    /*
     * Permet de supprimer un joueur (et la partie et ses evenements si la partie est vide)
     */

    public function delete() {
        if (sizeof($this->getJoueurs() != 0)) {
            foreach ($this->joueurs as $joueur)
                $joueur->delierPartie();
        }
        mysql_query("
                DELETE FROM evenement WHERE idpartie='$this->idPartie'");
        mysql_query("DELETE FROM partie
                WHERE idpartie='$this->idPartie'");
    }

    /**
     *  Getter sur $idpartie
     * @return int $idpartie
     */
    public function getIdPartie() {
        return $this->idPartie;
    }

    /**
     * Retourne "debut"
     * @return boolean 
     */
    public function getDebut() {
        return $this->debut;
    }

    /**
     *  Getter sur $nompartie
     * @return string $nompartie 
     */
    public function getNomPartie() {
        return $this->nomPartie;
    }

    /**
     *  Retourne le tableau des noms des joueurs
     * @return array<Joueur> Noms des joueurs
     * @author Cyril
     */
    public function getJoueurs() {
        log_it(__METHOD__, 1);
        $this->joueurs = array();
        $q = mysql_query("
            SELECT * FROM joueur
            WHERE idpartie=$this->idPartie ORDER BY place ASC");
        //log_it("Requete : SELECT * FROM joueur WHERE idpartie=$this->idPartie ORDER BY place ASC", 0);
        log_it("Erreurs : " . mysql_error(), 0);
        $r = array();
        while ($q && $d = mysql_fetch_array($q)) {
            $this->joueurs[$d["place"]] = $d["nomjoueur"];
            $r[$d["place"]] = new Joueur($d["nomjoueur"], $this->db);
        }
        log_it(json_encode($r), 0);
        log_it("/" . __METHOD__, -1);
        return $r;
    }

    /**
     *  Permet de recuperer les evenements depuis le dernier evenement recut
     * @param int $idEvenement dernier evenement recut
     * @param type $db
     * @return Evenement 
     */
    public function getEvenementSince($idEvenement, $db) {
        $idEvenement = mysql_real_escape_string($idEvenement);
        $q = mysql_query("
            SELECT * FROM evenement
            WHERE idevenement>$idEvenement AND idpartie='$this->idPartie' ORDER BY idevenement ASC");
        $r = array();
        while ($q && $d = mysql_fetch_array($q)) {
            $r[] = new Evenement($db, $d["idevenement"]);
        }
        return $r;
    }

    /**
     * Retourne le joueur a la position $position
     * @param int $position
     * @return Joueur 
     */
    public function getJoueur($position) {
        if(isset($this->joueurs[$position]))
            return new Joueur($this->joueurs[$position], $this->db);
        else return null;
    }

    /**
     *  Ajoute un joueur a la partie (équivalent a joueur->lierpartie)
     * @param Joueur $nomjoueur Nom du joueur a ajouter a la partie 
     * @author Cyril
     * @todo Mettre à jour le SQL
     */
    public function ajouterJoueur(Joueur $joueur) {
        //TODO SQLite
        if (in_array($joueur->getNom(), $this->joueurs))
            return true;
        if ($joueur->lierPartie($this)) {
            $this->joueurs[] = $joueur->getNom();
            return true;
        } return false;
    }

    /**
     *  Permet de passer au joueur suivant en fonction du sens
     * @return int Numero du joueur dont c'est le tours
     * @author Cyril
     */
    public function toursSuivant() {
        $positions = array_keys($this->getJoueurs());
        if ($this->sens == 1) {
            if ($this->tours == $positions[sizeof($positions)-1])
                $this->tours = $positions[0];
            else
                $this->tours=$positions[array_search($this->tours,$positions)+1];
        }
        else {
            if ($this->tours == $positions[0])
                $this->tours = $positions[sizeof($positions)-1];
            else
                $this->tours=$positions[array_search($this->tours,$positions)-1];
        }
        mysql_query("
                UPDATE partie SET tours = $this->tours WHERE idpartie='$this->idPartie'");
        Evenement::create("tour_de", $this->tours, $this, null);
        return $this->tours;
    }

    /**
     * Enclenche la distribution des cartes et la préparation de la partie
     * @return boolean True si tout se passe bien 
     */
    function commencer() {
        log_it(__METHOD__, 1);

        if ($this->debut == true) {
            log_it("La partie avait déjà commencé", 0);
            log_it("/" . __METHOD__, -1);
            return false;
        }
        $this->tours = rand(0, sizeof($this->joueurs) - 1);
        mysql_query("
                UPDATE partie SET debut=1, tours=" . $this->tours . " WHERE idpartie='$this->idPartie'");
        Evenement::create("event_commencer_partie", 0, $this, "");
        $cartes = $this->getTableauCartes();
        //$requete = "";
        //$requete .= "BEGIN;";
        foreach ($cartes as $carte) {
            /* $requete.="
              INSERT INTO evenement VALUES (
              NULL,
              'mouvement_carte',
              '$carte',
              4,
              {$this->idPartie});";// */
            Evenement::create("mouvement_carte", 4, $this, $carte);
        }
        // Mise de la première carte sur le Talon
        log_it("Préparation du talon", 0);
        do{
            $carte = $this->getCartePioche();
            Evenement::create("mouvement_carte", 5, $this, $carte);
        } while(carte::getCouleur($this->getCarteTalon())=="S");
        //$requete.="COMMIT;";
        //log_it($requete, 0);
        /* if (!sqlite_unbuffered_query($this->db, $requete)) {
          log_it("SQLITE_ERROR : " . sqlite_last_error($this->db), 0);
          exit(sqlite_last_error());
          } */
        $i = mysql_insert_id();
        //$erreur = sqlite_last_error();
        //log_it("Remplissage de la pioche (Dernier ID : $i ; erreur : $erreur)", 0);
        //Distribution des cartes aux joueurs
        log_it("Distribution aux joueurs", 0);
        for ($a = 0; $a < 7; $a++)
            foreach ($this->getJoueurs() as $joueur) {
                $joueur->piocher();
            }
        Evenement::create("tour_de", $this->tours, $this, "");
        log_it("/" . __METHOD__, -1);
        return true;
    }

    /**
     *  Getter sur Tours
     * @return int Numero du joueur dont c'est le tours
     * @author Cyril
     */
    public function getTours() {
        return $this->tours;
    }

    /**
     *  Inverse le sens du jeu
     * @return int 0 si le tours est inversé<br>1 sinon 
     * @author Cyril
     */
    public function inverserSens() {
        if ($this->sens == 1) {
            mysql_query("
                UPDATE partie SET sens = 0 WHERE idpartie=$this->idPartie");
            return $this->sens = 0;
        } else {
            mysql_query("
                UPDATE partie SET sens = 1 WHERE idpartie=$this->idPartie");
            return $this->sens = 1;
        }
    }

    /**
     * Retourne les parties rejoignables
     * @param SQLite_Resource $db DB SQLite
     * @return array<Partie> Liste des parties 
     */
    public static function getParties($db) {
        log_it(__METHOD__, 1);
        $r = array();
        $q = mysql_query("  SELECT * FROM partie p, joueur j
                            WHERE debut=0 AND p.idpartie=j.idpartie GROUP BY p.idpartie HAVING COUNT(j.nomjoueur)>0");
        log_it(mysql_error(), 0);
        while ($q && $d = mysql_fetch_array($q)) {
            $p = new Partie(intval($d["idpartie"]), $db);
            log_it('(' . json_encode($p->toarray()) . ')', 0);
            $r[] = $p->toarray();
        }
        log_it("/" . __METHOD__, -1);
        return $r;
    }

    /**
     *  Retourne un tableau contenant l'id, le nom et le nb de jrs
     * @return array Partie en tableau
     */
    public function toarray() {
        $r = array();
        $r['id_partie'] = $this->idPartie;
        $r['nom_partie'] = $this->nomPartie;
        $r['joueurs'] = sizeof($this->joueurs);
        return $r;
    }

    public function tobigarray() {
        $r = array();
        $r['id_partie'] = $this->idPartie;
        $r['nom_partie'] = $this->nomPartie;
        $r["joueurs"] = array();
        $r["debut"] = $this->debut;
        foreach ($this->getJoueurs() as $j)
            $r["joueurs"][] = $j->toarray();
        $r["evenements"] = array();
        $q = mysql_query("SELECT * FROM evenement WHERE idpartie=$this->idPartie");
        while ($q && $d = mysql_fetch_array($q)) {
            $e = new Evenement($this->db, $d["idevenement"]);
            $r["evenements"][] = $e->toArray();
        }

        return $r;
    }

    /**
     *  Retourne la position d'un joueur dans la partie
     * @param Joueur $joueur
     * @return type 
     */
    public function getPositionJoueur(Joueur $joueur) {
        log_it(__METHOD__, 1);
        $this->getJoueurs();
        log_it("/" . __METHOD__, -1);
        return array_search($joueur->getNom(), $this->joueurs);
    }

    public static function nettoyer($db) {
        $q = mysql_query("
            SELECT * FROM partie;");
        while ($q && $d = mysql_fetch_array($q)) {
            $partie = new Partie(intval($d["idpartie"]), $db);
            if (sizeof($partie->getJoueurs()) == 0) {
                $q = mysql_query("
            DELETE FROM partie WHERE idpartie={$partie->getIdPartie()}");
            }
        }
    }

    /**
     *  Recuperer la position d'une carte grace a son dernier mouvement
     * @param string $carte
     * @return int Position de la carte ou NULL si non initialisée 
     */
    public function getPositionCarte($carte) {
        log_it(__METHOD__, 1);
        $carte = mysql_real_escape_string($carte);
        $q = mysql_query("
            SELECT * FROM evenement
            WHERE type='mouvement_carte' AND data='$carte' AND idpartie=$this->idPartie ORDER BY idevenement DESC LIMIT 1");
        if ($q && $d = mysql_fetch_array($q)) {
            log_it("Position :({$d["destination"]})", 0);
            log_it("/" . __METHOD__, -1);
            return $d["destination"];
        } else
            log_it("Carte non initialisée", 0);
        log_it("/" . __METHOD__, -1);
        return null;
    }

    public function getDb() {
        return $this->db;
    }

    /**
     *  Permet de récuperer la dernière carte déposée par un joueur sur le talon
     * @return string carte
     */
    public function getCarteTalon() {
        $q = mysql_query("
            SELECT * FROM evenement
            WHERE type='mouvement_carte' && destination=5 && idpartie=$this->idPartie ORDER BY idevenement DESC LIMIT 1");
        if ($q && $d = mysql_fetch_array($q)) {
            return $d["data"];
        } else
            return null;
    }

    /**
     *  Permet de choisir la couleur de la carte, soit par rapport au dernier mouvement dans le talon soit par rapport au choix du joueur 
     * @return string carte
     */
    public function getCouleur() {
        $q1 = mysql_query("
            SELECT * FROM evenement
            WHERE type='mouvement_carte' AND destination=5 AND idpartie=$this->idPartie ORDER BY idevenement DESC LIMIT 1");
        $q2 = mysql_query("
            SELECT * FROM evenement
            WHERE type='changement_couleur' AND idpartie=$this->idPartie ORDER BY idevenement DESC LIMIT 1");
        if ($q1 && $d1 = mysql_fetch_array($q1)) {
            $d1["data"] = carte::getCouleur($d1["data"]);
            if ($q2 && $d2 = mysql_fetch_array($q2)) {
                if ($d1["idevenement"] > $d2["idevenement"])
                    return $d1["data"];
                return $d2["data"];
            }
            return $d1["data"];
        }else {
            if ($q2 && $d2 = mysql_fetch_array($q2))
                return $d2["data"];
            return null;
        }
    }

    public function getCartePioche() {
        log_it(__METHOD__, 1);
        $q = mysql_query("
            SELECT * FROM evenement
            WHERE type='mouvement_carte' AND destination=4 AND idpartie=$this->idPartie ORDER BY idevenement ASC");
        while ($q && $d = mysql_fetch_array($q)) {
            log_it("Carte analysée : {$d["data"]}", 0);
            if ($this->getPositionCarte($d["data"]) == 4) {
                log_it("({$d["data"]})", 0);
                log_it("/" . __METHOD__, -1);
                return $d["data"];
            }
        }
        log_it("Carte Non trouvée", 0);
        log_it("/" . __METHOD__, -1);
    }

    /*
     * function de supprimer un joueur depuis la base
     * SE REFERER A JOUEUR->delierpartie 
      public function suppression_joueur(int $position){
      $this->joueurs[$position];
      $q = sqlite_query($this->db, "
      DELETE FROM joueur
      WHERE idpartie=$this->idPartie && nomjoueur=$this->joueurs[$position]");
      return NULL;

      } */

    public function isPosable(Joueur $joueur, $carte) {
        $carte = mysql_real_escape_string($carte);
        log_it(__METHOD__, 1);
        if ($this->getPositionCarte($carte) != $this->getPositionJoueur($joueur) || $this->isBloquee()) {
            log_it("false", 0);
            log_it("/" . __METHOD__, -1);
            return false;
        }
        $carteTalon = $this->getCarteTalon();

        $sameCouleur = carte::getCouleur($carte) == $this->getCouleur();
        $sameValeur = ((carte::getValeur($carte) == carte::getValeur($carteTalon)) &&  carte::isSpecial($carteTalon)==carte::isSpecial($carte));
        if ($this->tours == $joueur->getPosition()) {
            //S'il reste des cartes a piocher
            if ($this->getCartesAPiocher() != 0) {
                //Si on ne met pas un + c'est pas bon
                if(carte::getValeur($carte) != "S") {
                    log_it("false:Cartes à piocher !", 0);
                    log_it("/" . __METHOD__, -1);
                    return false;
                    //Si c'est un +4, il faut poser un +4 Si c'est un +2, il faut un +2
                } elseif (carte::isSpecial($carteTalon) != carte::isSpecial($carte)) {
                    log_it("Le talon et la carte sont différents (Special et non-special)", 0);
                    log_it("/" . __METHOD__, -1);
                    return false;
                }
            }
            if (carte::isSpecial($carte)) {
                log_it("true:Carte Spéciale", 0);
                log_it("/" . __METHOD__, -1);
                return true;
            }
            if ($sameCouleur || $sameValeur) {
                log_it("true:Carte Compatible", 0);
                log_it("/" . __METHOD__, -1);
                return true;
            }
            log_it("false", 0);
            log_it("/" . __METHOD__, -1);
            return false;
        }
        /* if(carte::equal($carte, $this->getCarteTalon())){
          return true;
          } */
        log_it("false:Ce n'est pas le tour du joueur", 0);
        log_it("/" . __METHOD__, -1);
        return false;
    }

    public function isBloquee() {
        $qfin = mysql_query("
            SELECT * 
            FROM evenement 
            WHERE type='partie_terminee'
                AND idpartie=$this->idPartie");
        if(mysql_fetch_array($qfin)){
            log_it("Fin de la partie", 0);
            return true;
        }
        
        $q_couleur = mysql_query("
            SELECT * 
            FROM evenement 
            WHERE type='choisir_couleur'
                AND idpartie=$this->idPartie");
        if ($q_couleur && $d_couleur = mysql_fetch_array($q_couleur)) {
            $q_anticouleur = mysql_query("
            SELECT * 
            FROM evenement 
            WHERE type='changement_couleur'
                AND idpartie=$this->idPartie
                AND idevenement>{$d_couleur["idevenement"]}");
            if ($q_anticouleur && mysql_fetch_array($q_anticouleur)) {
                log_it("false", 0);
                log_it("/" . __METHOD__, -1);
                return false;
            }
            log_it("true", 0);
            log_it("/" . __METHOD__, -1);
            return true;
        }
        log_it("false", 0);
        log_it("/" . __METHOD__, -1);
        return false;
    }

    public function getCartesAPiocher() {
        log_it(__METHOD__, 1);
        $cartesAPiocher = 0;
        $idEvenement = 0;
        if (carte::getValeur($this->getCarteTalon()) == "S") {
            log_it("Carte malus detectée", 0);
            //On récupère la dernière carte piochée
            $q = mysql_query("SELECT * FROM evenement WHERE type='mouvement_carte' AND idpartie=$this->idPartie AND destination<4 ORDER BY idevenement DESC LIMIT 1");
            if ($d = mysql_fetch_array($q)) {
                log_it("Un joueur a pioché", 0);
                $idEvenement = $d["idevenement"];
            }
            $QcartesPosees = mysql_query("SELECT * FROM evenement WHERE type='mouvement_carte' AND idpartie=$this->idPartie AND idevenement>$idEvenement AND destination=5");
            log_it("Cartes posées : ".mysql_num_rows($QcartesPosees), 0);
            while ($cartesPosees = mysql_fetch_array($QcartesPosees)) {
                $cartesPosee = $cartesPosees["data"];
                log_it("Carte : " . $cartesPosee, 0);
                //Si c'est un +x
                if (carte::getValeur($cartesPosee) == "S") {
                    //C'est un spécial = +4
                    if (carte::getCouleur($cartesPosee) == "S") {
                        $cartesAPiocher+=4;
                    } else {
                        $cartesAPiocher+=2;
                    }
                }
            }
        }
        log_it($cartesAPiocher, 0);
        log_it("/" . __METHOD__, -1);
        return $cartesAPiocher;
    }

    

    public function finPartie(Joueur $gagnant){
        Evenement::create("partie_terminee", $gagnant->getPosition(), $this, $gagnant->getNom());
    }
    
    public function getTableauCartes() {
        log_it(__METHOD__, 1);
        $couleurN = array("R", "V", "B", "J");
        $valeurN = array(1, 2, 3, 4, 5, 6, 7, 8, 9, 0, "S", "I", "P");
        $couleur_valeurS = array("SJ", "SS");
        $cartes = array();
        foreach ($couleurN as $c) {
            foreach ($valeurN as $vn) {
                $maxN = 2;
                if ($vn === 0) {
                    $maxN = 1;
                }
                for ($a = 0; $a != $maxN; $a++) {
                    $cartes[] = $c . $vn . $a;
                }
            }
        }
        foreach ($couleur_valeurS as $vs) {
            $maxS = 4;
            for ($a = 0; $a != $maxS; $a++) {
                $cartes[] = $vs . $a;
            }
        }
        shuffle($cartes);
        $num = sizeof($cartes);
        log_it("($num)", 0);
        log_it("/" . __METHOD__, -1);
        return $cartes;
    }

}
